# 示例14 - 触发器优先级

说明

此示例演示如何使用触发器优先级来管理具有相同触发时间的触发器的触发顺序。

# 简析

本示例旨在演示Quartz中触发器优先级(Trigger Priorities)的使用。当多个触发器具有相同的触发时间时,可以通过设置优先级来控制它们的执行顺序。

该程序将执行以下操作:

  • 创建三个具有相同开始时间但不同优先级的触发器
  • 演示优先级如何影响首次触发顺序
  • 展示重复执行时优先级不再起作用(因为触发时间不同)

# 运行该示例

此示例可以从examples/example14目录中执行。有两种开箱即用的方法来运行此示例:

  • example14.sh——UNIX/Linux shell脚本
  • example14.bat——Windows批处理文件

# 代码

此示例的代码位于org.quartz.examples.example14包中。

本示例中的代码由以下类组成:

类名 描述
PriorityExample 主程序,演示触发器优先级的使用
TriggerEchoJob 一个简单输出触发器信息的作业

# TriggerEchoJob

TriggerEchoJob是一个简单的作业,它实现了Job接口,当被触发时会输出触发器的Key信息到日志中。这帮助我们观察不同触发器的执行顺序。

public void execute(JobExecutionContext context) throws JobExecutionException {
    LOG.info("TRIGGER: " + context.getTrigger().getKey());
}

# PriorityExample

程序首先创建一个调度器实例:

SchedulerFactory sf = new StdSchedulerFactory("org/quartz/examples/example14/quartz_priority.properties");
Scheduler sched = sf.getScheduler();

然后定义一个简单的作业:

JobDetail job = newJob(TriggerEchoJob.class).withIdentity("TriggerEchoJob").build();

接下来创建三个具有相同开始时间但不同优先级的触发器:

// 计算所有触发器的开始时间为5秒后
Date startTime = futureDate(5, IntervalUnit.SECOND);

// 第一个触发器优先级为1,5秒后重复
Trigger trigger1 = newTrigger().withIdentity("Priority1Trigger5SecondRepeat").startAt(startTime)
    .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(5)).withPriority(1).forJob(job).build();

// 第二个触发器默认优先级为5,10秒后重复
Trigger trigger2 = newTrigger().withIdentity("Priority5Trigger10SecondRepeat").startAt(startTime)
    .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(10)).forJob(job).build();

// 第三个触发器优先级为10,15秒后重复
Trigger trigger3 = newTrigger().withIdentity("Priority10Trigger15SecondRepeat").startAt(startTime)
    .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(15)).withPriority(10).forJob(job).build();

安排作业和触发器:

sched.scheduleJob(job, trigger1);
sched.scheduleJob(trigger2);
sched.scheduleJob(trigger3);

启动调度器并等待执行:

sched.start();
Thread.sleep(30L * 1000L); // 等待30秒
sched.shutdown(true);

# 预期执行顺序

根据代码中的注释,我们应该看到以下执行顺序:

首次执行(相同时间,按优先级排序):

  1. Priority10Trigger15SecondRepeat(优先级10)
  2. Priority5Trigger10SecondRepeat(优先级5)
  3. Priority1Trigger5SecondRepeat(优先级1)

重复执行(不同时间,忽略优先级): 4. Priority1Trigger5SecondRepeat(5秒后) 5. Priority5Trigger10SecondRepeat(10秒后) 6. Priority10Trigger15SecondRepeat(15秒后)

# 关键要点

  • 优先级范围:Quartz触发器优先级的默认值是5,可以设置为任意整数
  • 优先级规则:优先级数值越高,执行顺序越靠前
  • 适用场景:优先级只在多个触发器具有相同触发时间时才起作用
  • 重复执行:一旦触发器开始按不同间隔重复执行,执行顺序由实际触发时间决定,不再考虑优先级
  • 实际应用:在需要精确控制同时触发的作业执行顺序时非常有用

# TriggerEchoJob.java源码

package org.quartz.examples.example14;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * 这只是一个输出触发器名称的简单作业
 * 作者:Bill Kratzer
 */
public class TriggerEchoJob implements Job {

    private static final Logger LOG = LoggerFactory.getLogger(TriggerEchoJob.class);

    /**
     * 作业初始化的空参构造函数
     * Quartz需要一个公共的空参构造函数,以便调度器可以在需要时实例化类
     */
    public TriggerEchoJob() {
    }

    /**
     * 当与此作业相关联的触发器触发时,由调度器调用此方法
     * Throws:作业执行异常(JobExecutionException)-当执行作业时产生异常
     */
    public void execute(JobExecutionContext context)
        throws JobExecutionException {
        LOG.info("TRIGGER: " + context.getTrigger().getKey());
    }
}

# PriorityExample.java源码

package org.quartz.examples.example14;

import static org.quartz.DateBuilder.futureDate;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;

import org.quartz.DateBuilder.IntervalUnit;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

/**
 * 此示例将演示触发器如何按优先级排序
 * 作者:Bill Kratzer
 */
public class PriorityExample {

  public void run() throws Exception {
    Logger log = LoggerFactory.getLogger(PriorityExample.class);

    log.info("------- Initializing ----------------------");

    //首先,我们必须获得对调度器的引用
    SchedulerFactory sf = new StdSchedulerFactory("org/quartz/examples/example14/quartz_priority.properties");
    Scheduler sched = sf.getScheduler();

    log.info("------- Initialization Complete -----------");

    log.info("------- Scheduling Jobs -------------------");

    JobDetail job = newJob(TriggerEchoJob.class).withIdentity("TriggerEchoJob").build();

    // 所有三个触发器将在同一时间首次触发,
    // 按优先级排序,然后重复一次,以交错顺序触发,
    // 因此忽略优先级。
    //
    // 我们应该看到以下触发顺序:
    // 1. Priority10Trigger15SecondRepeat
    // 2. Priority5Trigger10SecondRepeat
    // 3. Priority1Trigger5SecondRepeat
    // 4. Priority1Trigger5SecondRepeat
    // 5. Priority5Trigger10SecondRepeat
    // 6. Priority10Trigger15SecondRepeat

    // 计算所有触发器的开始时间为5秒后
    Date startTime = futureDate(5, IntervalUnit.SECOND);

    // 第一个触发器优先级为1,5秒后重复
    Trigger trigger1 = newTrigger().withIdentity("Priority1Trigger5SecondRepeat").startAt(startTime)
        .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(5)).withPriority(1).forJob(job).build();

    // 第二个触发器默认优先级为5,10秒后重复
    Trigger trigger2 = newTrigger().withIdentity("Priority5Trigger10SecondRepeat").startAt(startTime)
        .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(10)).forJob(job).build();

    // 第三个触发器优先级为10,15秒后重复
    Trigger trigger3 = newTrigger().withIdentity("Priority10Trigger15SecondRepeat").startAt(startTime)
        .withSchedule(simpleSchedule().withRepeatCount(1).withIntervalInSeconds(15)).withPriority(10).forJob(job)
        .build();

    // 用我们的触发器通知Quartz安排该作业
    sched.scheduleJob(job, trigger1);
    sched.scheduleJob(trigger2);
    sched.scheduleJob(trigger3);

    //启动调度程序(在启动调度程序之前,任何东西都无法实际运行!)
    sched.start();
    log.info("------- Started Scheduler -----------------");

    //等待足够长的时间,以便调度器有机会执行该作业
    log.info("------- Waiting 30 seconds... -------------");
    try {
      Thread.sleep(30L * 1000L);
      //正在执行...
    } catch (Exception e) {
      //
    }

    //关闭调度器
    log.info("------- Shutting Down ---------------------");
    sched.shutdown(true);
    log.info("------- Shutdown Complete -----------------");
  }

  public static void main(String[] args) throws Exception {
    PriorityExample example = new PriorityExample();
    example.run();
  }
}

# 控制台输出

[main] INFO org.quartz.examples.example14.PriorityExample - ------- Initializing ----------------------
[main] INFO org.quartz.impl.StdSchedulerFactory - Using default implementation for ThreadExecutor
[main] INFO org.quartz.simpl.SimpleThreadPool - Job execution threads will use class loader of thread: main
[main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
[main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.3.0 created.
[main] INFO org.quartz.simpl.RAMJobStore - RAMJobStore initialized.
[main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.3.0) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
  Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.

[main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
[main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.3.0
[main] INFO org.quartz.examples.example14.PriorityExample - ------- Initialization Complete -----------
[main] INFO org.quartz.examples.example14.PriorityExample - ------- Scheduling Jobs -------------------
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
[main] INFO org.quartz.examples.example14.PriorityExample - ------- Started Scheduler -----------------
[main] INFO org.quartz.examples.example14.PriorityExample - ------- Waiting 30 seconds... -------------
[DefaultQuartzScheduler_Worker-1] INFO org.quartz.examples.example14.TriggerEchoJob - TRIGGER: DEFAULT.Priority10Trigger15SecondRepeat
[DefaultQuartzScheduler_Worker-2] INFO org.quartz.examples.example14.TriggerEchoJob - TRIGGER: DEFAULT.Priority5Trigger10SecondRepeat
[DefaultQuartzScheduler_Worker-3] INFO org.quartz.examples.example14.TriggerEchoJob - TRIGGER: DEFAULT.Priority1Trigger5SecondRepeat
[DefaultQuartzScheduler_Worker-4] INFO org.quartz.examples.example14.TriggerEchoJob - TRIGGER: DEFAULT.Priority1Trigger5SecondRepeat
[DefaultQuartzScheduler_Worker-5] INFO org.quartz.examples.example14.TriggerEchoJob - TRIGGER: DEFAULT.Priority5Trigger10SecondRepeat
[DefaultQuartzScheduler_Worker-6] INFO org.quartz.examples.example14.TriggerEchoJob - TRIGGER: DEFAULT.Priority10Trigger15SecondRepeat
[main] INFO org.quartz.examples.example14.PriorityExample - ------- Shutting Down ---------------------
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.
[main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.
[main] INFO org.quartz.examples.example14.PriorityExample - ------- Shutdown Complete -----------------

Process finished with exit code 0

微信公众号

QQ交流群
原创网站开发,偏差难以避免。

如若发现错误,诚心感谢反馈。

愿你倾心相念,愿你学有所成。

愿你朝华相顾,愿你前程似锦。